home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 19 / Amiga Plus Leser CD 19.iso / Tools / Freeware / Swf_Player / Lib / program.cc < prev    next >
Encoding:
C/C++ Source or Header  |  2002-11-17  |  23.3 KB  |  924 lines

  1. /////////////////////////////////////////////////////////////
  2. // Flash Plugin and Player
  3. // Copyright (C) 1998,1999 Olivier Debon
  4. // 
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. // 
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. // 
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18. // 
  19. ///////////////////////////////////////////////////////////////
  20. //  Author : Olivier Debon  <odebon@club-internet.fr>
  21. //  
  22.  
  23. #include "swf.h"
  24.  
  25. #include "amiga_specific.h"
  26.  
  27. #define NOTHING  0x0
  28. #define WAKEUP   0x1
  29. #define GOTO     0x2
  30. #define REFRESH  0x4
  31.  
  32. #ifdef RCSID
  33. static char *rcsid = "$Id: program.cc,v 1.4 1999/09/03 15:17:41 ode Exp $";
  34. #endif
  35.  
  36. #define PRINT 0
  37.  
  38. int debug = 0;
  39.  
  40. Program::Program(FlashMovie *movie, long n)
  41. {
  42.     long f;
  43.  
  44.         this->movie = movie;
  45.  
  46.     totalFrames = 0;
  47.  
  48.     dl = new DisplayList(movie);
  49.     if (dl == NULL) return;
  50.     frames = new Frame[n];
  51.     if (frames == NULL) {
  52.         delete dl;
  53.         return;
  54.     }
  55.  
  56.     nbFrames = 0;
  57.     totalFrames = n;
  58.     currentFrame = 0;
  59.     loadingFrame = 0;
  60.     movieWait = 1;
  61.     nextFrame = currentFrame;
  62.     for(f = 0; f < n; f++)
  63.     {
  64.         frames[f].controls = 0;
  65.         frames[f].label = NULL;
  66.     }
  67.  
  68.     movieStatus = MoviePlay;
  69.     settings = 0;
  70. }
  71.  
  72. Program::~Program()
  73. {
  74.     int i;
  75.     Control *ctrl, *ctrl1;
  76.  
  77.     delete dl;
  78.  
  79.     if (frames != NULL) {
  80.         for(i=0;i<nbFrames;i++) {
  81.         ctrl = frames[i].controls;
  82.         if (frames[i].label) free(frames[i].label);
  83.         while (ctrl != NULL) {
  84.             ctrl1 = ctrl->next;
  85.             ctrl->next = NULL;
  86.             delete ctrl;
  87.             ctrl = ctrl1;
  88.         }
  89.         }
  90.  
  91.         delete[] frames;
  92.     }
  93. }
  94.  
  95. void
  96. Program::validateLoadingFrame()
  97. {
  98.     nbFrames = loadingFrame;
  99.     loadingFrame++;
  100.     movieWait = 0;
  101. }
  102.  
  103. Frame    *
  104. Program::getFrames()
  105. {
  106.     return frames;
  107. }
  108.  
  109. long
  110. Program::getNbFrames()
  111. {
  112.     return nbFrames;
  113. }
  114.  
  115. DisplayList *
  116. Program::getDisplayList()
  117. {
  118.     return dl;
  119. }
  120.  
  121. long
  122. Program::getCurrentFrame()
  123. {
  124.     return currentFrame;
  125. }
  126.  
  127. void
  128. Program::setCurrentFrame(long n)
  129. {
  130.     currentFrame = n;
  131.     nextFrame = n;
  132.     //refresh = 1;
  133. }
  134.  
  135. void
  136. Program::gotoFrame(GraphicDevice *gd, long frame)
  137. {
  138.     long f;
  139.  
  140.     //printf("GotoFrame %d  (Current = %d)\n", frame, currentFrame);
  141.     dl->clearList();
  142.  
  143.     for(f=0; f <= frame; f++) {
  144.         runFrame(gd, 0, f, 0);
  145.     }
  146. }
  147.  
  148. long
  149. Program::runFrame(GraphicDevice *gd, SoundMixer *sm, long f, long action)
  150. {
  151.     Control        *ctrl;
  152.     Character    *character;
  153.     Matrix        *matrix;
  154.     Cxform        *cxform;
  155.     long         status = NOTHING;
  156.     long         update = 0;
  157.     char        *name;
  158.  
  159. #if PRINT&1
  160.     if (action) printf("Prog %x (dl=%x): Frame N° %d/%d\n", this, this->dl, f, nbFrames-1);
  161. #endif
  162.         movie->buttons_updated = 0;
  163.  
  164.     for(ctrl = frames[f].controls; ctrl; ctrl = ctrl->next)
  165.     {
  166.         switch (ctrl->type)
  167.         {
  168.             case ctrlPlaceObject:
  169.             case ctrlPlaceObject2:
  170.                 character = 0;
  171.                 matrix = 0;
  172.                 cxform = 0;
  173.                 name = "";
  174.                 if (ctrl->flags & placeHasCharacter) {
  175.                     character = ctrl->character;
  176.                 }
  177.                 if (ctrl->flags & placeHasMatrix) {
  178.                     matrix = &ctrl->matrix;
  179.                 }
  180.                 if (ctrl->flags & placeHasColorXform) {
  181.                     cxform = &ctrl->cxform;
  182.                 }
  183.                 if (ctrl->flags & placeHasName) {
  184.                     name = ctrl->name;
  185.                 }
  186.                 if (!ctrl->clipDepth) {    // Ignore
  187.                     dl->placeObject(gd,character, ctrl->depth, matrix, cxform, name);
  188.                     update = 1;
  189.                 }
  190.                 break;
  191.             case ctrlRemoveObject:
  192.                 character = ctrl->character;
  193.  
  194.                 if (!character) break;    // Should not happen
  195.  
  196.                 dl->removeObject(gd, character, ctrl->depth);
  197.                 if (action) {
  198.                     character->reset();
  199.                     update = 1;
  200.                 }
  201.                 break;
  202.             case ctrlRemoveObject2:
  203.                 character = dl->removeObject(gd,NULL, ctrl->depth);
  204.                 if (character && action) {
  205.                     character->reset();
  206.                     update = 1;
  207.                 }
  208.                 break;
  209.         // Actions
  210.             case ctrlDoAction:
  211.                 if (action) {
  212.                     status = doAction(gd, ctrl->actionRecords, sm);
  213.                 }
  214.                 break;
  215.             case ctrlStartSound:
  216.                 if (action && sm) {
  217.                     sm->startSound( (Sound *)ctrl->character );
  218.                 }
  219.                 break;
  220.             case ctrlStopSound:
  221.                 if (action && sm) {
  222.                     sm->stopSounds();
  223.                 }
  224.                 break;
  225.             case ctrlBackgroundColor:
  226.                 if (action) {
  227.                     if (gd->setBackgroundColor(ctrl->color)) {
  228.                         dl->bbox.xmin = -32768;
  229.                         dl->bbox.ymin = -32768;
  230.                         dl->bbox.xmax =  32768;
  231.                         dl->bbox.ymax =  32768;
  232.                     }
  233.                 }
  234.                 break;
  235.         }
  236.     }
  237.         if (movie->buttons_updated) {
  238.             dl->updateButtons(movie);
  239.         }
  240.  
  241.     if (status & GOTO) {
  242.         if (nextFrame < nbFrames) {
  243.             gotoFrame(gd,nextFrame);
  244.             if (nextFrame != f)
  245.             if (movieStatus == MoviePaused) runFrame(gd,sm,nextFrame);
  246.             update = 1;
  247.         }
  248.     }
  249.  
  250. #if PRINT&1
  251.     if (action) printf("Frame N° %d ready\n", f);
  252. #endif
  253.     return update;
  254. }
  255.  
  256. long
  257. Program::nestedMovie(GraphicDevice *gd, SoundMixer *sm, Matrix *mat, Cxform *cxform)
  258. {
  259.     if (movieStatus == MoviePlay) {
  260.         // Movie Beeing Played
  261.         advanceFrame();
  262.         if (currentFrame == 0) {
  263.             dl->clearList();
  264.         }
  265.         runFrame(gd, sm, currentFrame);
  266.         if (nbFrames == 1) {
  267.             pauseMovie();
  268.         }
  269.     }
  270.  
  271.     return (movieStatus == MoviePlay);
  272. }
  273.  
  274. long
  275. Program::processMovie(GraphicDevice *gd, SoundMixer *sm)
  276. {
  277.     int wakeUp = 0;
  278.  
  279. #if PRINT&1
  280.     printf("Prog %x (dl=%x): Current = %d     Next = %d    Wait = %d  Status = %d\n", this, this->dl, currentFrame, nextFrame, movieWait, movieStatus);
  281. #endif
  282.  
  283.     if (movieStatus == MoviePlay && movieWait == 0) {
  284.         // Movie Beeing Played
  285.         advanceFrame();
  286.         if (currentFrame == 0) {
  287.             dl->clearList();
  288.         }
  289.         wakeUp |= runFrame(gd, sm, currentFrame);
  290.         wakeUp |= dl->updateSprites();
  291.         if (nextFrame == nbFrames) {
  292.             if (nbFrames != totalFrames) {
  293.                 movieWait = 1;
  294.             } else if ((settings & PLAYER_LOOP) == 0) {
  295.                 pauseMovie();
  296.             }
  297.         }
  298.     } else {
  299.         wakeUp |= dl->updateSprites();
  300.     }
  301.  
  302.     if (wakeUp) {
  303.         render = 1;
  304.     }
  305.  
  306.     return (wakeUp || movieStatus == MoviePlay);
  307. }
  308.  
  309. /* timer (ms) -1 = delete timer */
  310. void setFlashTimer(struct myTimeval *tv, int time_ms)
  311. {
  312.     if (time_ms == -1) {
  313.         tv->tv_sec = -1;
  314.     } else {
  315.         gettimeofday(tv,0);
  316.         
  317.         tv->tv_usec += time_ms*1000;
  318.         while (tv->tv_usec > 1000000) {
  319.             tv->tv_usec -= 1000000;
  320.             tv->tv_sec++;
  321.         }
  322.     }
  323. }
  324.  
  325. int checkFlashTimer(struct myTimeval *tv)
  326. {
  327.     struct myTimeval now;
  328.  
  329.     if (tv->tv_sec == -1) return 0;
  330.  
  331.     gettimeofday(&now,0);
  332.     return (now.tv_sec > tv->tv_sec ||
  333.             (now.tv_sec == tv->tv_sec && now.tv_usec >= tv->tv_usec));
  334. }
  335.  
  336. /* bbox */
  337. typedef struct {
  338.     long x1,y1,x2,y2;
  339. } ButtonBoundingBox;
  340.  
  341.  
  342. static void button_bbox_func(void *id, long y, long start, long end)
  343. {
  344.     ButtonBoundingBox *h = (ButtonBoundingBox *) id;
  345.  
  346.     if (y < h->y1) h->y1 = y;
  347.     if (y > h->y2) h->y2 = y;
  348.     if (start < h->x1) h->x1 = start;
  349.     if (end > h->x2) h->x2 = end;
  350. }
  351.  
  352. void computeBBox(FlashMovie *movie, Rect *rect, DisplayListEntry *e)
  353. {
  354.     ButtonBoundingBox bb;
  355.  
  356.     bb.x1 = LONG_MAX;
  357.     bb.y1 = LONG_MAX;
  358.     bb.x2 = LONG_MIN;
  359.     bb.y2 = LONG_MIN;
  360.     
  361.     e->character->getRegion(movie->gd,&e->renderMatrix,&bb,button_bbox_func);
  362.     
  363.     rect->xmin = bb.x1 / FRAC;
  364.     rect->xmax = bb.x2 / FRAC;
  365.     rect->ymin = bb.y1;
  366.     rect->ymax = bb.y2;
  367. }
  368.  
  369. void transform_coords(long *x_ptr,long *y_ptr, long cx, long cy, long dx, long dy)
  370. {
  371.     long x,y,x1,y1;
  372.     x = *x_ptr;
  373.     y = *y_ptr;
  374.  
  375.     x -= cx;
  376.     y -= cy;
  377.  
  378.     if (dx < 0) {
  379.         /* left */
  380.         x1 = - x;
  381.         y1 = y;
  382.     } else if (dy < 0) {
  383.         /* up */
  384.         y1 = x;
  385.         x1 = -y;
  386.     } else if (dy > 0) {
  387.         /* down */
  388.         y1 = x;
  389.         x1 = y;
  390.     } else {
  391.         /* right */
  392.         x1 = x;
  393.         y1 = y;
  394.     }
  395.         
  396.     *x_ptr = x1;
  397.     *y_ptr = y1;
  398. }
  399.  
  400. typedef struct {
  401.     FlashMovie *movie;
  402.     DisplayListEntry *emin,*cur_focus;
  403.     long dmin;
  404.     long w,cx,cy,dx,dy;
  405. } ButtonFocus;
  406.  
  407. static int button_focus(void *opaque, Program *prg, DisplayListEntry *e)
  408. {
  409.     ButtonFocus *h=(ButtonFocus *)opaque;
  410.     Rect rect;
  411.     long d,x,y;
  412.  
  413.     if (e != h->cur_focus) {
  414.         computeBBox(h->movie,&rect,e);
  415.         x = (rect.xmin + rect.xmax) / 2;
  416.         y = (rect.ymin + rect.ymax) / 2;
  417.         
  418.         /* transform the coords so that the angular sector is directed to the right */
  419.         transform_coords(&x,&y,h->cx,h->cy,h->dx,h->dy);
  420.         
  421.         /* inside it ? */
  422.         if ( x >= 0 && 
  423.              (y - x - h->w) <= 0 && 
  424.              (y + x + h->w) >= 0) {
  425.             d = x*x + y*y;
  426.             
  427.             if (d < h->dmin) {
  428.                 h->dmin = d;
  429.                 h->emin = e;
  430.             }
  431.         }
  432.     }
  433.     return 0;
  434. }
  435.  
  436. DisplayListEntry *moveFocus(FlashMovie *movie, long dx, long dy, 
  437.                             DisplayListEntry *cur_focus)
  438. {
  439.     Rect cur_rect;
  440.     ButtonFocus h;
  441.  
  442.     h.movie = movie;
  443.     h.dx = dx;
  444.     h.dy = dy;
  445.  
  446.     computeBBox(movie,&cur_rect,cur_focus);
  447.     /* center */
  448.     h.cx = (cur_rect.xmin + cur_rect.xmax) / 2;
  449.     h.cy = (cur_rect.ymin + cur_rect.ymax) / 2;
  450.     
  451.     /* width/2 of the 45 degrees angular sector */
  452.     if (dy != 0) {
  453.         /* for vertical displacement, we have a larger width */
  454.         h.w = (cur_rect.xmax - cur_rect.xmin) / 2;
  455.     } else {
  456.         /* zero width for horizontal displacement */
  457.         h.w = 0;
  458.     }
  459.  
  460.     /* now we select the nearest button in the angular sector */
  461.     h.dmin = LONG_MAX;
  462.     h.emin = NULL;
  463.     h.cur_focus = cur_focus;
  464.  
  465.     exploreButtons(movie, &h, button_focus);
  466.     
  467.     return h.emin;
  468. }
  469.  
  470. static int button_newfocus(void *opaque, Program *prg, DisplayListEntry *e)
  471. {
  472.     * (DisplayListEntry **)opaque = e;
  473.     return 2;
  474. }
  475.  
  476. static int button_nextfocus(void *opaque, Program *prg, DisplayListEntry *e)
  477. {
  478.     static int found = 0;
  479.     DisplayListEntry **focus;
  480.  
  481.     focus = (DisplayListEntry **)opaque;
  482.     if (found) {
  483.         *focus = e;
  484.     found = 0;
  485.     return 2;
  486.     }
  487.     if (e == *focus) {
  488.         found = 1;
  489.     }
  490.     return 0;
  491. }
  492.  
  493.  
  494. /* XXX: should not be here (one level upper) */
  495. long
  496. Program::handleEvent(GraphicDevice *gd, SoundMixer *sm, FlashEvent *fe)
  497. {
  498.     ActionRecord    *action;
  499.     Program        *prog;
  500.     long         status = 0;
  501.     DisplayListEntry *cur_focus, *new_focus;
  502.     long dx,dy;
  503.     int             refresh;
  504.  
  505.     refresh = 0;
  506.  
  507.     switch(fe->type) {
  508.  
  509.     case FeKeyRelease:
  510.         if (movie->mouse_active == 0) {
  511.             
  512.             if (movie->cur_focus) {
  513.         movie->cur_focus->owner->updateBoundingBox(movie->cur_focus);
  514.                 movie->cur_focus->renderState = stateOver;
  515.         movie->cur_focus->owner->updateBoundingBox(movie->cur_focus);
  516.             }
  517.         }
  518.         break;
  519.  
  520.     case FeKeyPress:
  521.  
  522.         movie->mouse_active = 0;
  523.  
  524.         /* find the button which has the focus */
  525.         cur_focus = movie->cur_focus;
  526.  
  527.         if (fe->key == FeKeyEnter) {
  528.             /* selection */
  529.             if (cur_focus) {
  530.                 /* select the button */
  531.         cur_focus->owner->updateBoundingBox(cur_focus);
  532.                 cur_focus->renderState = stateDown;
  533.             ((Button *)cur_focus->character)->updateButtonState(cur_focus);
  534.         cur_focus->owner->updateBoundingBox(cur_focus);
  535.  
  536.                 movie->scheduledEvent.type = FeKeyRelease;
  537.                 movie->scheduledEvent.key = FeKeyEnter;
  538.  
  539.                 setFlashTimer(&movie->scheduledTime, 250); /* 250 ms down */
  540.             }
  541.         } else {
  542.             /* displacement */
  543.  
  544.             if (cur_focus == NULL) {
  545.                 /* no current focus : set one */
  546.                 exploreButtons(movie, &cur_focus, button_newfocus);
  547.                 if (cur_focus) {
  548.                     cur_focus->renderState = stateOver;
  549.             ((Button *)cur_focus->character)->updateButtonState(cur_focus);
  550.             cur_focus->owner->updateBoundingBox(cur_focus);
  551.                 }
  552.                 movie->cur_focus = cur_focus;
  553.             } else {
  554.                 /* move the focus (test) */
  555.                 switch(fe->key) {
  556.                 case FeKeyNext:
  557.                     /* Next available */
  558.             cur_focus->owner->updateBoundingBox(cur_focus);
  559.                     cur_focus->renderState = stateUp;
  560.             ((Button *)cur_focus->character)->updateButtonState(cur_focus);
  561.             cur_focus->owner->updateBoundingBox(cur_focus);
  562.                     exploreButtons(movie, &cur_focus, button_nextfocus);
  563.                     if (cur_focus) {
  564.                         cur_focus->renderState = stateOver;
  565.                 ((Button *)cur_focus->character)->updateButtonState(cur_focus);
  566.                 cur_focus->owner->updateBoundingBox(cur_focus);
  567.                     }
  568.                     movie->cur_focus = cur_focus;
  569.                     dx = 0;
  570.                     dy = 0;
  571.             break;
  572.                 case FeKeyUp:
  573.                     dx = 0;
  574.                     dy = -1;
  575.                     break;
  576.                 case FeKeyDown:
  577.                     dx = 0;
  578.                     dy = 1;
  579.                     break;
  580.                 case FeKeyLeft:
  581.                     dx = -1;
  582.                     dy = 0;
  583.                     break;
  584.                 case FeKeyRight:
  585.                     dx = 1;
  586.                     dy = 0;
  587.                     break;
  588.                 default:
  589.                     /* should not happen */
  590.                     dx = 0;
  591.                     dy = 0;
  592.                     break;
  593.                 }
  594.  
  595.                 if (dx != 0 || dy != 0) {
  596.  
  597.                     new_focus = moveFocus(movie, dx, dy, cur_focus);
  598.                     if (new_focus) {
  599.             cur_focus->owner->updateBoundingBox(cur_focus);
  600.                         cur_focus->renderState = stateUp;
  601.             ((Button *)cur_focus->character)->updateButtonState(cur_focus);
  602.             cur_focus->owner->updateBoundingBox(cur_focus);
  603.  
  604.                 if (computeActions(movie, &prog, &action)) {
  605.                 status |= prog->doAction(gd, action, sm);
  606.                 }
  607.                 
  608.                         new_focus->renderState = stateOver;
  609.             ((Button *)new_focus->character)->updateButtonState(new_focus);
  610.                         movie->cur_focus = new_focus;
  611.             new_focus->owner->updateBoundingBox(new_focus);
  612.                     } else {
  613.                 return 0;
  614.             }
  615.                 }
  616.             }
  617.         if (movie->cur_focus == NULL) return 0;
  618.         }
  619.         break;
  620.  
  621.     case FeMouseMove:
  622.         movie->mouse_active = 1;
  623.         movie->mouse_x = fe->x * FRAC;
  624.         movie->mouse_y = fe->y * FRAC;
  625.         dl->updateButtons(movie);
  626.         break;
  627.  
  628.     case FeButtonPress:
  629.         movie->mouse_active = 1;
  630.         movie->button_pressed = 1;
  631.         dl->updateButtons(movie);
  632.         break;
  633.  
  634.     case FeButtonRelease:
  635.         movie->mouse_active = 1;
  636.         movie->button_pressed = 0;
  637.         dl->updateButtons(movie);
  638.         break;
  639.         
  640.     default:
  641.         return 0;
  642.     }
  643.  
  644.     if (computeActions(movie, &prog, &action)) {
  645.         status |= prog->doAction(gd, action, sm);
  646.     }
  647.  
  648.     if (status & REFRESH) {
  649.         status |= WAKEUP;
  650.         refresh = 1;
  651.     }
  652.     if (status & GOTO) {
  653.         if (nextFrame < nbFrames) {
  654.         gotoFrame(gd, nextFrame);
  655.         if (movieStatus == MoviePaused) runFrame(gd,sm,nextFrame);
  656.         refresh = 1;
  657.     }
  658.     }
  659.  
  660.     if (refresh) {
  661.         dl->updateSprites();
  662.         render = 1;
  663.     }
  664.     return (refresh || movieStatus == MoviePlay);
  665. }
  666.  
  667. long
  668. Program::doAction(GraphicDevice *gd, ActionRecord *action, SoundMixer *sm)
  669. {
  670.     long status = NOTHING;
  671.         long f;
  672.     char *target = "";
  673.     long skip = 0;
  674.  
  675.     while(action)
  676.     {
  677.         if (skip) skip--;
  678.         else
  679.         switch (action->action)
  680.         {
  681.             case ActionPlaySound:
  682. #if PRINT&2
  683.                 printf("Prog %x : PlaySound\n", this);
  684. #endif
  685.                                 if (sm) {
  686.                                     sm->startSound(action->sound);
  687.                                 }
  688.                 status |= WAKEUP;
  689.                 break;
  690.             case ActionRefresh:
  691. #if PRINT&2
  692.                 printf("Prog %x : Refresh\n", this);
  693. #endif
  694.                 status |= REFRESH;
  695.                 break;
  696.             case ActionGotoFrame:
  697. #if PRINT&2
  698.                 printf("Prog %x : GotoFrame %d\n", this, action->frameIndex);
  699. #endif
  700.                 if (target[0] == 0) {
  701.                     if (action->frameIndex < nbFrames) {
  702.                         currentFrame = action->frameIndex;
  703.                         pauseMovie();
  704.                         status |= WAKEUP|GOTO;
  705.                     }
  706.                 }
  707.                 break;
  708.             case ActionGetURL:
  709. #if PRINT&2
  710.                 printf("Prog %x : GetURL %s target = %s\n", this, action->url, action->target);
  711. #endif
  712.                                 {
  713.                                     int len,level;
  714.                                     len = strlen(action->target);
  715.                                     
  716.                                     if (len > 6 && memcmp(action->target,"_level", 6) == 0) {
  717.                                         level = atoi(action->target + 6);
  718.                                         loadNewSwf(movie, action->url, level);
  719.                                     } else {
  720.                                         if (movie->getUrl) {
  721.                                             movie->getUrl(action->url, action->target, movie->getUrlClientData);
  722.                                         }
  723.                                     }
  724.                                 }
  725.                 break;
  726.             case ActionNextFrame:
  727.                 nextFrame = currentFrame+1;
  728.                 movieStatus = MoviePlay;
  729.                 status |= WAKEUP;
  730.                 break;
  731.             case ActionPrevFrame:
  732.                 nextFrame = currentFrame-1;
  733.                 status |= WAKEUP|GOTO;
  734.                 break;
  735.             case ActionPlay:
  736. #if PRINT&2
  737.                 printf("Prog %x : Play\n", this);
  738. #endif
  739.                 if (target[0] == 0) {
  740.                     movieStatus = MoviePlay;
  741.                     if ((status & GOTO) == 0) {
  742.                         if (currentFrame == nextFrame) advanceFrame();
  743.                     }
  744.                     status |= WAKEUP;
  745.                 }
  746.                 break;
  747.             case ActionStop:
  748. #if PRINT&2
  749.                 printf("Prog %x : Stop\n", this);
  750. #endif
  751.                 if (target[0] == 0) {
  752.                     movieStatus = MoviePaused;
  753.                     nextFrame = currentFrame;
  754.                 }
  755.                 break;
  756.             case ActionToggleQuality:
  757.                 break;
  758.             case ActionStopSounds:
  759.                 if (sm) {
  760.                     sm->stopSounds();
  761.                 }
  762.                 break;
  763.             case ActionWaitForFrame:
  764.                 if (action->frameIndex >= nbFrames) {
  765.                     skip = action->skipCount;
  766.                 }
  767.                 break;
  768.             case ActionSetTarget:
  769. #if PRINT&2
  770.                 printf("Prog %x : SetTarget '%s'\n", this, action->target);
  771. #endif
  772.                 target = action->target;
  773.                 break;
  774.             case ActionGoToLabel:
  775. #if PRINT&2
  776.                 printf("Prog %x : GotoFrame '%s'\n", this, action->frameLabel);
  777. #endif
  778.                                 f = searchFrame(gd, action->frameLabel, target);
  779.                                 if (f >= 0) {
  780.                     currentFrame = f;
  781.                     pauseMovie();
  782.                                     status |= WAKEUP|GOTO;
  783.                                 } else {
  784.                                     status |= REFRESH;
  785.                                 }
  786.                 break;
  787.         }
  788.         action = action->next;
  789.     }
  790.     return status;
  791. }
  792.  
  793. void
  794. Program::setCurrentFrameLabel(char *label)
  795. {
  796.     frames[loadingFrame].label = label;
  797. }
  798.  
  799. void
  800. Program::rewindMovie()
  801. {
  802.     currentFrame = 0;
  803.     nextFrame = 0;
  804. }
  805.  
  806. void
  807. Program::pauseMovie()
  808. {
  809.     movieStatus = MoviePaused;
  810.     nextFrame = currentFrame;
  811. }
  812.  
  813. void
  814. Program::continueMovie()
  815. {
  816.     movieStatus = MoviePlay;
  817. }
  818.  
  819. void
  820. Program::nextStepMovie()
  821. {
  822.     if (movieStatus == MoviePaused) {
  823.         advanceFrame();
  824.     }
  825. }
  826.  
  827. void
  828. Program::advanceFrame()
  829. {
  830.     currentFrame = nextFrame;
  831.     nextFrame = currentFrame+1;
  832.     if (currentFrame == nbFrames) {
  833.         currentFrame = 0;
  834.         nextFrame = 0;
  835.         movieStatus = MoviePlay;
  836.     }
  837. }
  838.  
  839. void
  840. Program::addControlInCurrentFrame(Control *ctrl)
  841. {
  842.     Control *c;
  843.  
  844.     ctrl->next = 0;
  845.     if (frames[loadingFrame].controls == 0) {
  846.         frames[loadingFrame].controls = ctrl;
  847.     } else {
  848.         for(c = frames[loadingFrame].controls; c->next; c = c->next);
  849.         c->next = ctrl;
  850.     }
  851. }
  852.  
  853. void
  854. Program::modifySettings(long flags)
  855. {
  856.     settings = flags;
  857. }
  858.  
  859. long
  860. Program::searchFrame(GraphicDevice *gd, char *label, char *target)
  861. {
  862.     long f;
  863.         DisplayListEntry *e;
  864.         Program *prg;
  865.  
  866.     // Current movie
  867.     if (target[0] == 0) {
  868.         for(f=0; f < nbFrames; f++)
  869.         {
  870.             if (frames[f].label && !strcmp(label,frames[f].label)) {
  871.             return f;
  872.             }
  873.         }
  874.     }
  875.  
  876.     // Kludge !!!
  877.     for (e = dl->list; e; e = e->next) {
  878.         if (e->character->isSprite()) {
  879.         prg = ((Sprite *)e->character)->program;
  880.         f = prg->searchFrame(gd,label,"");
  881.         if (f >= 0 && f < prg->nbFrames) {
  882.             prg->dl->updateBoundingBox(e);
  883.             prg->gotoFrame(gd, f);
  884.             prg->nextFrame = f;
  885.             prg->dl->updateBoundingBox(e);
  886.             return -1;
  887.         }
  888.         }
  889.     }
  890.  
  891.     return -1;
  892. }
  893.  
  894. void loadNewSwf(FlashMovie *movie, char *url, int level)
  895. {
  896.     CInputScript *s,*prev,**l;
  897.  
  898.     if (movie->getSwf == NULL) return;
  899.  
  900.     for(s = movie->main, prev = 0; s != NULL; prev = s, s = s->next) {
  901.         if (s->level == level) {
  902.         // Mark movie to be deleted
  903.         s->level = -1;
  904.         break;
  905.     }
  906.     }
  907.  
  908.     //printf("Unload movie @ %d\n", level);
  909.  
  910.     if (*url == 0) return;    // Just UnloadMovie
  911.  
  912.     s = new CInputScript(level);
  913.     if (s == NULL) return;
  914.  
  915.     /* insert it in the right order */
  916.     l = &movie->main;
  917.     while (*l != NULL && (*l)->level < level) l = &(*l)->next;
  918.     s->next = *l;
  919.     *l = s;
  920.  
  921.     // Notify the external loader of a new movie to load
  922.     movie->getSwf(url, level, movie->getSwfClientData);
  923. }
  924.